/*
 * @Author: mei
 * @Date: 2021-05-08 15:20:29
 * @LastEditTime: 2021-05-08 15:21:54
 * @LastEditors: Please set LastEditors
 * @Description: 包含了stl的基本算法
 * @FilePath: /mei/project/MySTL/STL/algobase.h
 */
#ifndef MYSTL_ALGOBASE_H
#define MYSTL_ALGOBASE_H

#include<cstring>

#include "util.h"
#include "iterator.h"

namespace mystl {
    /******************max***********************/
    template<class T>
    const T &max(const T &t1, const T &t2) {
        return t1 > t2 ? t1 : t2;
    }

    //重载版本comp
    template<class T, class Comp>
    T &max(const T &t1, const T &t2, Comp comp) {
        return comp(t1, t2) ? t1 : t2;
    };

    /******************min***********************/
    template<class T>
    const T &min(const T &t1, const T &t2) {
        return t1 > t2 ? t2 : t1;
    }

    //重载版本comp
    template<class T, class Comp>
    T &min(const T &t1, const T &t2, Comp comp) {
        return comp(t1, t2) ? t1 : t2;
    };

    /******************iter_swap***********************/
    template<class Iter1, class Iter2>
    void iter_swap(Iter1 iter1, Iter2 iter2) {
        mystl::swap(*iter1, *iter2);
    };

    /******************copy***********************/
    //input_iterator_tag版本
    template<class InputIterator, class OutputIterator>
    OutputIterator unchecked_copy_cat(
            InputIterator first, //头
            InputIterator last,  //尾
            OutputIterator out,  //新的头
            mystl::input_iterator_tag) { //如果是输入型的迭代器就进入到当前函数
        for (; first != last; ++first, ++out) {
            *out = *first;
        }
        return out;
    };

    //random_iterator_tag版本
    template<class RondomIterator, class OutputIterator>
    OutputIterator unchecked_copy_cat(
            RondomIterator first, //头
            RondomIterator last,  //尾
            OutputIterator out,  //新的头
            mystl::random_access_iterator_tag) { //如果是输入型的迭代器就进入到当前函数
        for (auto n = last - first; n > 0; --n, ++first, ++out) {
            *out = *first;
        }
        return out;
    };

    template<class InputIterator, class OutputIterator>
    OutputIterator unchecked_copy(InputIterator first, InputIterator last, OutputIterator out) {
        return unchecked_copy_cat(first, last, out, iterator_category(first));
    };

    // 为 trivially_copy_assignable 类型提供特化版本
    template<class Tp, class Up>
    typename std::enable_if<
            std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
            std::is_trivially_copy_assignable<Up>::value,
            Up *>::type
    unchecked_copy(Tp *first, Tp *last, Up *result) {
        const auto n = static_cast<size_t>(last - first);
        if (n != 0)
            std::memmove(result, first, n * sizeof(Up));
        return result + n;
    }

    template<class InputIter, class OutputIter>
    OutputIter copy(InputIter first, InputIter last, OutputIter result) {
        return unchecked_copy(first, last, result);
    }

/*****************************************************************************************/
// copy_backward
// 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内
/*****************************************************************************************/
// unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本
    template<class BidirectionalIter1, class BidirectionalIter2>
    BidirectionalIter2
    unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,
                                BidirectionalIter2 result, mystl::bidirectional_iterator_tag) {
        while (first != last)
            *--result = *--last;
        return result;
    }

// unchecked_copy_backward_cat 的 random_access_iterator_tag 版本
    template<class BidirectionalIter1, class BidirectionalIter2>
    BidirectionalIter2
    unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last,
                                BidirectionalIter2 result, mystl::random_access_iterator_tag) {
        for (auto n = last - first; n > 0; --n)
            *--result = *--last;
        return result;
    }

    template<class BidirectionalIter1, class BidirectionalIter2>
    BidirectionalIter2
    unchecked_copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,
                            BidirectionalIter2 result) {
        return unchecked_copy_backward_cat(first, last, result,
                                           iterator_category(first));
    }

// 为 trivially_copy_assignable 类型提供特化版本
    template<class Tp, class Up>
    typename std::enable_if<
            std::is_same<typename std::remove_const<Tp>::type, Up>::value &&
            std::is_trivially_copy_assignable<Up>::value,
            Up *>::type
    unchecked_copy_backward(Tp *first, Tp *last, Up *result) {
        const auto n = static_cast<size_t>(last - first);
        if (n != 0) {
            result -= n;
            std::memmove(result, first, n * sizeof(Up));
        }
        return result;
    }

    template<class BidirectionalIter1, class BidirectionalIter2>
    BidirectionalIter2
    copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result) {
        return unchecked_copy_backward(first, last, result);
    }

    // copy_if  带条件的复制
    template<class InputIter, class OutputIter, class UnaryPredicate>
    OutputIter
    copy_if(InputIter first, InputIter last, OutputIter res, UnaryPredicate comp) {
        for (; first != last; ++first) {
            if (comp(*first)) { //当成立的时候才会往后面移动
                *res++ = *first;
            }
        }
        return res;
    };

    //copy_n 带个数的复制  返回一对pair  分别指向头和尾
    template<class InputIter, class Size, class OutputIter>
    mystl::pair<OutputIter, OutputIter>
    unchecked_copy_n(
            InputIter first,
            Size n,
            OutputIter res,
            mystl::input_iterator_tag) {
        for (; n > 0; ++first, n--, ++res) {
            *res = *first;
        }
        return mystl::pair<InputIter, OutputIter>(first, res);
    };

    template<class RandomIter, class Size, class OutputIter>
    mystl::pair<RandomIter, OutputIter>
    unchecked_copy_n(RandomIter first, Size n, OutputIter result,
                     mystl::random_access_iterator_tag) {
        auto last = first + n;
        return mystl::pair<RandomIter, OutputIter>(last, mystl::copy(first, last, result));
    }

    template<class InputIter, class Size, class OutputIter>
    mystl::pair<OutputIter, OutputIter>
    copy_n(InputIter first, Size n, OutputIter result) {
        return unchecked_copy_n(first, n, result, iterator_category(first));
    };


}
#endif
